Матч
306, Подсчет путей (TourCounting)
Дивизион 1,
Уровень 3
В ориентированном графе g следует найти количество разных циклов длины,
меньшей k. Результат следует вернуть
по модулю m.
Циклом называется непустая последовательность вершин, последовательно соединенных
ребрами, причем между последней вершиной и первой существует ребро. Два цикла
считаются разными, если их последовательности не идентичны.
Ячейка g[i][j] равна ‘Y’, если
существует ребро, соединяющее i -ое
ребро с j -ым. Иначе g[i][j]
равно ‘N’.
Класс: TourCounting
Метод: int countTours(vector<string> g, int k, int m)
Ограничения:
g содержит от 1 до 35 строк одинаковой длины, состоящих из
букв ‘Y’ и ‘N’, 1 £ k £ 106, 1 £ m £ 109.
Вход. Массив строк g, описывающий матрицу
смежности графа, целые числа k и m.
Выход. Количество разных циклов длины, меньшей k. Результат вернуть по модулю m.
Пример входа
g |
k |
m |
{"NYNY", "NNYN", "YNNN", "YNNN"} |
6 |
100 |
{"NYNNNNN", "NNYNNNN", "NNNYNNN", "NNNNYNN", "NNNNNYN", "NNNNNNY", "YNNNNNN"} |
40 |
13 |
{"NYNY", "NNNN", "YYNY", "NYNN"} |
1000000 |
1000000000 |
Пример выхода
12
9
0
РЕШЕНИЕ
алгебра + графы
Теорема. Пусть А – матрица смежности графа. Тогда Ak[i][j] содержит количество
путей, ведущих из i -ой вершины в j -ую, и имеющих длину k. Число циклов, имеющих длину k, равно сумме диагональных элементов
матрицы Ak.
Определение. Следом матрицы
называется сумма ее диагонльных элементов.
Количество разных циклов длины,
меньшей k, равно сумме диагональных
элементов матрицы S = A + A2 + A3 + … + Ak-1. Возведение в
степень Ak можно совершить
за O(log k). Рассмотрим алгоритм
вычисления матрицы S за время O(log k).
Пусть функция sum(k) вычисляет значение суммы A + A2
+ … + Ak, а pow(k) находит Ak.
Если k четное, то
sum(k) = A + A2 + … + Ak
= A + A2 + … + Ak/2
+ Ak/2+1 + … + Ak
=
= (A + A2 + … + Ak/2) + Ak/2 * (A + A2
+ … + Ak/2) =
= sum(k / 2) * pow(k / 2) +
sum(k / 2)
Если k нечетное, то
sum(k) = A + A2 + … + Ak
=
(A + A2 + … + Ak – 1) * A + A =
sum(k – 1) * A + A
Ответом на поставленную задачу
будет значение следа матрицы sum(k –
1).
ПРОГРАММА
#include <cstdio>
#include <string>
#include <vector>
using namespace std;
typedef vector<int> vi;
typedef vector<vector<int>
> vvi;
vvi add(vvi a,vvi b, int mod)
{
int i, j, n = a.size();
vvi c(n, vi(n));
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
c[i][j] = (a[i][j] + b[i][j]) % mod;
return c;
}
vvi mult(vvi a,vvi b, int mod)
{
int i, j, k, s, n = a.size();
vvi c(n, vi(n));
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
{
for(s = k = 0; k < n; k++) s = (s + (long long)a[i][k] *
b[k][j]) % mod;
c[i][j] = s;
}
return c;
}
vvi pow(vvi a, int
k, int mod)
{
int i, n = a.size();
vvi res(n, vi(n, 0));
for(i = 0; i < n; i++) res[i][i] = 1;
while (k > 0)
{
if (k % 2) res = mult(res, a, mod);
a = mult(a, a, mod);
k /= 2;
}
return res;
}
vvi sum(vvi a, int
k, int mod)
{
if (k == 1) return a;
if (k % 2)
{
vvi temp = sum(a,k-1,mod);
return add(mult(temp,a,mod),a,mod);
}
vvi temp = sum(a,k/2,mod);
vvi powk_2 = pow(a,k/2,mod);
return add(mult(temp,powk_2,mod),temp,mod);
}
class TourCounting
{
public:
int countTours(vector<string> g, int k, int m)
{
int i, j, n = g.size();
vvi mas(n, vi(n, 0));
long long
res;
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
if (g[i][j] == 'Y')
mas[i][j] = 1; else mas[i][j] = 0;
res = 0;
vvi temp = sum(mas,k-1,m);
for(i = 0; i < n; i++)
res = (res + temp[i][i]) % m;
return res;
}
};